#include <algorithm>

#include "metrics/Counter.hpp"
#include "metrics/Histogram.hpp"
#include "metrics/Gauge.hpp"
#include "metrics/MetricRegistry.hpp"

namespace metrics
{

    template <typename T>
    void collect_all(std::vector<MetricFamily> &results, const T &families)
    {
        for (auto &collectable : families)
        {
            auto metrics = collectable->collect();
            results.insert(results.begin(), std::make_move_iterator(metrics.begin()), std::make_move_iterator(metrics.end()));
        }
    }

    MetricRegistry::MetricRegistry()
    {
    }

    MetricRegistry::~MetricRegistry()
    {
    }

    template <>
    std::vector<std::shared_ptr<Family<Counter>>> &MetricRegistry::families<Counter>()
    {
        return _counters;
    }

    template <>
    std::vector<std::shared_ptr<Family<Gauge>>> &MetricRegistry::families<Gauge>()
    {
        return _gauges;
    }

    template <>
    std::vector<std::shared_ptr<Family<Histogram>>> &MetricRegistry::families<Histogram>()
    {
        return _histograms;
    }

    std::vector<MetricFamily> MetricRegistry::collect() const
    {
        std::lock_guard<std::mutex> lock{_mutex};
        std::vector<MetricFamily> results;
        results.reserve(_counters.size() + _gauges.size() + _histograms.size());

        collect_all(results, _counters);
        collect_all(results, _gauges);
        collect_all(results, _histograms);

        return results;
    }

} // namespace metrics